using System;
using System.IO;
using System.Data;
using System.Xml;
using System.Web;
using System.Web.UI;
using System.Diagnostics;

namespace ControlExplorer.samples.GroupWare
{
  public class LoadDataSetXML
  {
    private const String document = "GroupWare.xml";
    private const String schema = "GroupWare.xsd";
    private XmlDataDocument myXmlDataDocument;

    // loads defaults if only path is given
    public LoadDataSetXML(String appPath)
      : this(appPath, document, schema)
    {
    }

    // loads XML data and schema files with a path to the files
    public LoadDataSetXML(String appPath, String loadDocument, String loadSchema)
    {
      // retrieve the path name
      String pathname = HttpContext.Current.Server.MapPath(appPath + "//");
      // load the requested XML file and XML schema
      this.Load(pathname + loadDocument, pathname + loadSchema);
    }

    // no path specified, use any path embedded in document and schema parameters 
    public LoadDataSetXML(String loadDocument, String loadSchema)
    {
      // load the requested XML file and XML schema
      this.Load(loadDocument, loadSchema);
    }

    public void Load(String loadDocument, String loadSchema)
    {
      try
      {
        Debug.WriteLine("Creating an XmlDataDocument ...");
        // create a new XML data document to hold the data
        myXmlDataDocument = new XmlDataDocument();
        // parse the requested schema
        ParseSchema(loadSchema);
        // output the table structure for debugging
        // does not affect release code, comment out for faster debug run
        DisplayTableStructure();

        // load the XML document with external data
        myXmlDataDocument.Load(loadDocument);

        // output the data for debugging 
        // does not affect release code, comment out for faster debug run
        DisplayTables(myXmlDataDocument.DataSet);
      }
      catch (Exception e)
      {
        Debug.WriteLine("Exception: {0}", e.ToString());
      }
    }

    // retrieve the dataset from the loaded XML document class
    public DataSet GetDataSet()
    {
      if (myXmlDataDocument == null)
        return null;
      else
        return myXmlDataDocument.DataSet;

    }

    // Loads a specified schema into the DataSet
    public void ParseSchema(String loadSchema)
    {
      StreamReader myStreamReader = null;

      try
      {
        Debug.WriteLine("Reading Schema file ...");
        // open a stream to read the schema
        myStreamReader = new StreamReader(loadSchema);
        // reads schema
        myXmlDataDocument.DataSet.ReadXmlSchema(myStreamReader);
      }

      catch (Exception e)
      {
        Debug.WriteLine("Exception: {0}", e.ToString());
      }

      finally
      {
        // close stream, if necessary
        if (myStreamReader != null)
          myStreamReader.Close();
      }
    }

    // Displays the DataSet tables structure only at debugging
    private void DisplayTableStructure()
    {
      Debug.WriteLine("Table structure \r\n");
      Debug.WriteLine("Tables count=" + myXmlDataDocument.DataSet.Tables.Count.ToString());
      for (int i = 0; i < myXmlDataDocument.DataSet.Tables.Count; i++)
      {
        Debug.WriteLine("\r\nTableName='" + myXmlDataDocument.DataSet.Tables[i].TableName + "'.");
        Debug.WriteLine("Columns count=" + myXmlDataDocument.DataSet.Tables[i].Columns.Count.ToString());

        for (int j = 0; j < myXmlDataDocument.DataSet.Tables[i].Columns.Count; j++)
        {
          Debug.WriteLine("\tColumnName='" + myXmlDataDocument.DataSet.Tables[i].Columns[j].ColumnName + "', type = " + myXmlDataDocument.DataSet.Tables[i].Columns[j].DataType.ToString());
        }
      }
    }

    // Displays the contents of the DataSet tables only at debugging
    private void DisplayTables(DataSet dataset)
    {
      // Navigate Dataset
      Debug.WriteLine("\r\nContent of Tables ...");

      foreach (DataTable table in dataset.Tables)
      {
        Debug.WriteLine("TableName = " + table.TableName);
        Debug.WriteLine("{0}", "---------");
        Debug.WriteLine("Columns ...");

        foreach (DataColumn column in table.Columns)
        {
          Debug.Write(column.ColumnName);
        }
        Debug.WriteLine("\r\nNumber of rows = " + table.Rows.Count.ToString());
        Debug.WriteLine("Rows ...");

        foreach (DataRow row in table.Rows)
        {
          foreach (Object value in row.ItemArray)
          {
            Debug.Write(value.ToString());
          }
          Debug.WriteLine("");
        }
        Debug.WriteLine("");
      }
    }

  } // End class LoadDataSetXML

  public class SaveDataSetXML
  {
    private const String document = "GroupWare.xml";
    private const String schema = "GroupWare.xsd";

    // saves to defaults if only path and dataset are given
    public SaveDataSetXML(String appPath, DataSet saveDS)
      : this(appPath, saveDS, document, schema)
    {
    }

    // saves XML data and schema files with a path to the files in document and schema parameters
    public SaveDataSetXML(String appPath, DataSet saveDS, String saveDocument, String saveSchema)
    {
      // retrieve the path name
      String pathname = HttpContext.Current.Server.MapPath(appPath + "//");
      // save to the requested XML data file and XML schema file
      this.Save(saveDS, pathname + saveDocument, pathname + saveSchema);
    }

    // no path specified, use any path embedded in document and schema parameters 
    public SaveDataSetXML(DataSet saveDS, String saveDocument, String saveSchema)
    {
      // save the requested XML data file and XML schema
      this.Save(saveDS, saveDocument, saveSchema);
    }

    public void Save(DataSet saveDS, String saveDocument, String saveSchema)
    {
      try
      {
        // output the tables for debugging
        // does not affect release code, comment out for faster debug run
        DisplayTables(saveDS);

        // write out schema representation
        saveDS.WriteXmlSchema(saveSchema);

        // write out XML data relational data
        saveDS.WriteXml(saveDocument, XmlWriteMode.IgnoreSchema);

        // create an XmlDataDocument for the DataSet
        XmlDataDocument datadoc = new XmlDataDocument(saveDS);

        // output the data for debugging 
        // does not affect release code, comment out for faster debug run
        DisplayXMLData(datadoc);
      }
      catch (Exception e)
      {
        Debug.WriteLine("Exception: {0}", e.ToString());
      }
    }

    // Display the contents of the DataSet only at debugging
    public void DisplayTables(DataSet myDataSet)
    {
      try
      {
        if (myDataSet == null)
        {
          Debug.WriteLine("The DataSet is null");
          return;
        }

        Debug.WriteLine("\r\nDataSet: \r\n" + myDataSet.DataSetName + " contains ...");

        // Navigate Dataset
        Debug.WriteLine("No of Tables: " + myDataSet.Tables.Count.ToString() + "  Table content ...\r\n");
        foreach (DataTable table in myDataSet.Tables)
        {
          Debug.WriteLine("TableName = " + table.TableName);
          Debug.WriteLine("---------");
          Debug.WriteLine("Columns ...\r\n");
          foreach (DataColumn column in table.Columns)
          {
            Debug.Write(column.ColumnName);
          }
          Debug.WriteLine("\r\nNumber of rows = " + table.Rows.Count.ToString());
          Debug.WriteLine("Rows ...\r\n");
          foreach (DataRow row in table.Rows)
          {
            foreach (Object value in row.ItemArray)
            {
              Debug.Write(value.ToString());
            }
            Debug.WriteLine("");
          }
          Debug.WriteLine("");
        }

        // relationships

        for (int i = 0; i < myDataSet.Relations.Count; i++)
        {
          Debug.WriteLine(myDataSet.Relations[i].RelationName);
        }

        Debug.WriteLine("");

        // 
        foreach (DataRow dItem in myDataSet.Tables["employees"].Rows)
        {
          Debug.WriteLine("Manager = " + dItem["first_name"] + " " + dItem["last_name"] + " manages");
          foreach (DataRow teamMbr in dItem.GetChildRows(myDataSet.Relations["groupMembers"]))
          {
            Debug.WriteLine("\tGroupMember = " + teamMbr["first_name"] + " " + teamMbr["last_name"]);
          }
          Debug.WriteLine("");
          foreach (DataRow appointment in dItem.GetChildRows(myDataSet.Relations["schedules"]))
          {
            Debug.WriteLine("\tAppointment = " + appointment["description"] + " " + appointment["date"]);
          }
        }
      }
      catch (Exception e)
      {
        Debug.WriteLine("Exception: {0}", e.ToString());
      }
    }


    // Display data as XML only at debugging
    public void DisplayXMLData(XmlDataDocument datadoc)
    {
      XmlNodeReader myXmlNodeReader = null;

      try
      {
        Debug.WriteLine("Displaying the XML ...\r\n");
        myXmlNodeReader = new XmlNodeReader(datadoc.SelectSingleNode("/"));
        FormatXml(myXmlNodeReader);
      }
      catch (Exception e)
      {
        Debug.WriteLine("Exception: {0}", e.ToString());
      }
      finally
      {
        if (myXmlNodeReader != null)
          myXmlNodeReader.Close();
      }
    }

    // format the XML correctly
    private static void FormatXml(XmlReader reader)
    {
      while (reader.Read())
      {
        switch (reader.NodeType)
        {
          case XmlNodeType.ProcessingInstruction:
            Format(reader, "ProcessingInstruction");
            break;
          case XmlNodeType.DocumentType:
            Format(reader, "DocumentType");
            break;
          case XmlNodeType.Document:
            Format(reader, "Document");
            break;
          case XmlNodeType.Comment:
            Format(reader, "Comment");
            break;
          case XmlNodeType.Element:
            Format(reader, "Element");
            while (reader.MoveToNextAttribute())
            {
              Format(reader, "Attribute");
            }
            break;
          case XmlNodeType.Text:
            Format(reader, "Text");
            break;
          case XmlNodeType.Whitespace:
            Format(reader, "Whitespace");
            break;
        }
      }
    }

    // Format the output
    private static void Format(XmlReader reader, String NodeType)
    {
      // Format the output
      for (int i = 0; i < reader.Depth; i++)
      {
        Debug.Write('\t');
      }

      Debug.Write(NodeType + "<" + reader.Name + ">" + reader.Value);
      Debug.WriteLine("");
    }

  } // End class SaveDataSetXML

}